package cn.yunyichina.provider.pay.service;

import cn.yunyichina.provider.iface.entity.dto.pacity.PacityRefundRequestDTO;
import cn.yunyichina.provider.iface.entity.wechat.WechatMedicalRefundRequest;
import cn.yunyichina.provider.pay.constant.Pacity;
import cn.yunyichina.provider.pay.entity.PaymentSetting;
import cn.yunyichina.provider.pay.exception.PaySettingNotFoundException;
import cn.yunyichina.utils.commons.DateUtils;
import cn.yunyichina.utils.commons.NumberUtil;
import cn.yunyichina.utils.commons.RandomUtil;
import cn.yunyichina.utils.convert.JsonUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Lullaby on 2016/10/27.
 */
public class BaseRefundService extends BaseService {

    protected boolean checkAlipayOrWechatRefundParameters(Map<String, String> params) {
        if (CollectionUtils.isEmpty(params)) return false;
        if (StringUtils.isEmpty(params.get("app_id"))) return false;
        if (StringUtils.isEmpty(params.get("order_no"))
                && StringUtils.isEmpty(params.get("pay_order_no"))) return false;
        if (StringUtils.isEmpty(params.get("total_fee"))) return false;
        if (StringUtils.isEmpty(params.get("refund_fee"))) return false;
        return true;
    }

    protected boolean checkWechatMedicalRefundParameters(Map<String, String> params) {
        if (CollectionUtils.isEmpty(params)) return false;
        if (StringUtils.isEmpty(params.get("app_id"))) return false;
        if (StringUtils.isEmpty(params.get("order_no"))) return false;
        if (StringUtils.isEmpty(params.get("hosp_out_trade_no"))) return false;
        if (StringUtils.isEmpty(params.get("hosp_out_refund_no"))) return false;
        if (StringUtils.isEmpty(params.get("cancel_serial_no"))) return false;
        return true;
    }

    protected Map<String, String> buildWechatRefundParameters(Map<String, String> params) throws PaySettingNotFoundException {
        Map<String, String> result = new HashMap<>();

        PaymentSetting paymentSetting = this.getPaymentSetting(params.get("app_id"));

        result.put("appid", paymentSetting.getPayAppId());
        result.put("mch_id", paymentSetting.getMerchantAccount());
        result.put("nonce_str", RandomUtil.getRandomALLChar(32));
        if (!StringUtils.isEmpty(params.get("order_no"))) {
            result.put("out_trade_no", params.get("order_no"));
        }
        if (!StringUtils.isEmpty(params.get("pay_order_no"))) {
            result.put("transaction_id", params.get("pay_order_no"));
        }
        result.put("out_refund_no", NumberUtil.buildPaymentDealNo());
        result.put("total_fee", params.get("total_fee"));
        result.put("refund_fee", params.get("refund_fee"));
        result.put("op_user_id", paymentSetting.getMerchantAccount());
        result.put("api_secret", paymentSetting.getPayKey());

        return result;
    }

    protected WechatMedicalRefundRequest buildWechatMedicalRefundRequest (Map<String, String> params, String accessToken, String apiSecret) {
        WechatMedicalRefundRequest request = new WechatMedicalRefundRequest();
        request.setAppid(params.get("appid"));
        request.setSubAppid(params.get("sub_appid"));
        request.setMchId(params.get("mch_id"));
        request.setSubMchId(params.get("sub_mch_id"));
        request.setNonceStr(RandomUtil.getRandomALLChar(32));
        request.setHospOutTradeNo(params.get("order_no"));
//        request.setHospOutRefundNo(params.get("order_no"));
        request.setHospOutRefundNo(params.get("hosp_out_refund_no"));

        request.setAccessToken(accessToken);
        request.setApiSecret(apiSecret);

        request.setCancelSerialNo(params.get("cancel_serial_no"));

        String cancelBillNo = params.get("cancel_bill_no");
        if (!StringUtils.isEmpty(cancelBillNo)) {
            request.setCancelBillNo(cancelBillNo);
        }

        return request;
    }

    protected Map<String, String> buildAlipayRefundParameters
            (Map<String, String> params) throws PaySettingNotFoundException {
        Map<String, String> result = new HashMap<>();

        PaymentSetting paymentSetting = this.getPaymentSetting(params.get("app_id"));
        String signType = "RSA";
        if (paymentSetting.getPayPublicKey().length() > 256) {
            signType = "RSA2";
        }

        result.put("private_key", paymentSetting.getPrivateKey());
        result.put("public_key", paymentSetting.getPublicKey());
        result.put("pay_public_key", paymentSetting.getPayPublicKey());

        result.put("app_id", paymentSetting.getPayAppId());
        result.put("method", "alipay.trade.refund");
        result.put("format", "JSON");
        result.put("charset", "utf-8");
        result.put("sign_type", signType);
        result.put("timestamp", DateUtils.dateToString(Calendar.getInstance().getTime()));
        result.put("version", "1.0");

        Map<String, Object> businessParams = new HashMap<>();
        String orderNo = params.get("order_no");
        if (!StringUtils.isEmpty(orderNo)) {
            businessParams.put("out_trade_no", orderNo);
        }
        String payOrderNo = params.get("pay_order_no");
        if (!StringUtils.isEmpty(payOrderNo)) {
            businessParams.put("trade_no", payOrderNo);
        }
        businessParams.put("refund_amount",
                new BigDecimal(params.get("refund_fee")).divide(
                        new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        businessParams.put("out_request_no", NumberUtil.buildPaymentDealNo());

        String cancelSerialNo = params.get("cancel_serial_no");
        String cancelBillNo = params.get("cancel_bill_no");
        if (!StringUtils.isEmpty(cancelSerialNo) && !StringUtils.isEmpty(cancelBillNo)) {
            Map<String, String> medicalParams = new HashMap<>();
            medicalParams.put("cancel_serial_no", cancelSerialNo);
            medicalParams.put("cancel_bill_no", cancelBillNo);
            businessParams.put("extend_params", medicalParams);
        }

        result.put("biz_content", JsonUtils.toJsonString(businessParams));

        return result;
    }

    protected boolean checkPacityRefundParameters(Map<String, String> params) {
        if (StringUtils.isEmpty(params.get("app_id"))) return false;

        if (StringUtils.isEmpty(params.get("total_fee"))) return false;
        if (StringUtils.isEmpty(params.get("refund_fee"))) return false;
        if (StringUtils.isEmpty(params.get("order_no"))) return false;

        return true;
    }

    protected PacityRefundRequestDTO buildPacityRefundRequestDTO(Map<String, String> params) throws Exception {
        String appId = params.get("app_id");
        PaymentSetting paymentSetting = getPaymentSetting(appId);

        PacityRefundRequestDTO requestDTO = new PacityRefundRequestDTO();
        requestDTO.setAccessToken(getPacityAccessToken());
        requestDTO.setPublicKey(paymentSetting.getPayPublicKey());
        requestDTO.setPrivateKey(paymentSetting.getPrivateKey());

        requestDTO.setPlatMchId(paymentSetting.getMerchantAccount());
        requestDTO.setNonceStr(RandomUtil.getRandomALLChar(32));
        requestDTO.setPlatMchTradeNo(params.get("order_no"));

        String platRefundNo = NumberUtil.buildPaymentDealNo();
        requestDTO.setPlatMchRefundNo(platRefundNo);

        requestDTO.setTotalAmt(new BigDecimal(params.get("refund_fee")).divide(
                new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        requestDTO.setRefundAmt(new BigDecimal(params.get("total_fee")).divide(
                new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        requestDTO.setOpUserId(Pacity.OPUSERID);

        String cancelSerialNo = params.get("cancel_serial_no");
        String cancelBillNo = params.get("cancel_bill_no");
        if (!StringUtils.isEmpty(cancelSerialNo) && !StringUtils.isEmpty(cancelBillNo)) {
            requestDTO.setMchTradeNo(platRefundNo);
            requestDTO.setMchBizSN(cancelSerialNo);
            requestDTO.setMchBillNo(cancelBillNo);
        }

        return requestDTO;
    }

}
